#ifdef spy

// some functions for debugging uses

static int tmp1,tmp2;
//static FILE *tfp;

#include <pngwriter.h>

struct CHSL {
  static short ToRGB(double rm1, double rm2, double rh) 
  {
         if(rh>360) rh-=360;
    else if(rh<  0) rh+=360;

         if(rh< 60) rm1=rm1+(rm2-rm1)*rh/60;   
    else if(rh<180) rm1=rm2;
    else if(rh<240) rm1=rm1+(rm2-rm1)*(240-rh)/60;      

    return (short)(0.5+rm1*255);
  }
  static void RGB2HSL(short& R, short& G, short& B, short& H, short& S, short& L) 
  {
    R=std::min(std::max(short(0),R),short(255));
    G=std::min(std::max(short(0),G),short(255));
    B=std::min(std::max(short(0),B),short(255));
    short minval=std::min(std::min(R,G),B);
    short maxval=std::max(std::max(R,G),B);
    long msum =maxval+minval;
    L=(short)(0.5+(msum*240/510.));
    if(maxval==minval) 
    {
      S=0;
      H=160;
    }
    else
    {
      double delta=(double)maxval-minval;

      S=(short)(0.5+(240*(delta/((msum<=255) ? msum : (510-msum)))));

      double h;
           if(R==maxval) h=40*(  (G-B)/delta);
      else if(G==maxval) h=40*(2+(B-R)/delta);
      else if(B==maxval) h=40*(4+(R-G)/delta);
      if(h>240) h-=240;
      if(h<  0) h+=240;
      H=(short)(0.5+h);
    }
  }
  static void HSL2RGB(short& R, short& G, short& B, short& _H, short& _S, short& _L) 
  {
    _H=std::min(std::max(short(0),_H),short(239));
    _S=std::min(std::max(short(0),_S),short(240));
    _L=std::min(std::max(short(0),_L),short(240));
    double H=_H*360/240.0f;
    double S=_S/240.0f;
    double L=_L/240.0f;
    if(S) 
    {
      double rm2;
      if(_L<=120) rm2=L+  L*S;  
      else        rm2=L+S-L*S;
      double rm1=2*L-rm2;   
      R=ToRGB(rm1, rm2, H+120);   
      G=ToRGB(rm1, rm2, H);
      B=ToRGB(rm1, rm2, H-120);
    }
      else R=G=B=(short)(0.5+L*255);
  }
};
static void hsl2rgb(double h, double s, double l, double *r, double *g, double *b)
{
    short H = short(h * 240 + 0.5);
    short S = short(s * 240 + 0.5);
    short L = short(l * 240 + 0.5);
    short R, G, B;
    CHSL::HSL2RGB(R,G,B, H,S,L);
    *r = R / 255.0;
    *g = G / 255.0;
    *b = B / 255.0;
}

class mapper
{
public:
    mapper(double x1, double x2, double y1, double y2) : X1(x1),X2(x2),Y1(y1),Y2(y2),RC(1.0) 
    {
        RC = (y1 - y2) / (x1 - x2);
    }
    double map(double x)
    {
        return Y2 + RC * (x - X2);
    }
private:
    double X1,X2,Y1,Y2,RC;    
};

static char code(double value)
{
    if (value > -0.00000000001 && value < 0.00000000001)
        return '.';
    if (value < 0)
        return '=';
    return '#';
}

#define magnify 4

static void PlotArray(const std::string &file, const Array2D<REAL> &a, int s1, int e1, int s2, int e2)
{
    unsigned n1 = e1 - s1 + 1;
    unsigned n2 = e2 - s2 + 1;
    REAL minimum = a[0][0];
    REAL maximum = a[0][0];
    REAL mean = 0;
    for (int i1 = s1; i1 <= e1; ++i1) 
    { 
        for (int i2 = s2; i2 <= e2; ++i2)
        {
            minimum = std::min(minimum, a[i1][i2]);
            maximum = std::max(maximum, a[i1][i2]);
            mean += a[i1][i2];
        } 
    } 
    mean /= (n1 * n2);
    mapper m(minimum, maximum, 0.0, 0.67);
    mapper dm(minimum - mean, maximum - mean, 0.0, 0.67);
    mapper dn(0, maximum - minimum, 0.0, 0.67);
    char buffer[200];
    sprintf(buffer,"%s(range%f#%f).png",file.c_str(),minimum,maximum);
    pngwriter image(magnify * n1, magnify * n2, 1.0, buffer);
//    sprintf(buffer,"%s(mean%f).png",file.c_str(),mean);
//    pngwriter diffimage(magnify * n1, magnify * n2, 1.0, buffer);
//    sprintf(buffer,"%s(minimum%f).png",file.c_str(),minimum);
//    pngwriter minimage(magnify * n1, magnify * n2, 1.0, buffer);
    for (int i1 = s1; i1 <= e1; ++i1) 
    { 
        for (int i2 = s2; i2 <= e2; ++i2)
        {
            double value = a[i1][i2];
            for (int w = 0; w < 3; ++w)
            {
                if (w ==1)
                    value = a[i1][i2] - mean;
                if (w==2)
                    value = a[i1][i2] - minimum;
                if (value > -0.00000000001 && value < 0.00000000001)
                {
                    for (int ii = 0; ii < magnify; ++ii)
                    {
                        for (int jj = 0; jj < magnify; ++jj)
                        {
                            switch (w)
                            {
                                case 0: image.plot    (magnify * (i1 - s1) + ii, magnify * (i2 - s2) + jj, 0, 0, 0); break;
//                                case 1: diffimage.plot(magnify * (i1 - s1) + ii, magnify * (i2 - s2) + jj, 0, 0, 0); break;
//                                case 2: minimage.plot (magnify * (i1 - s1) + ii, magnify * (i2 - s2) + jj, 0, 0, 0); break;
                            }
                        }
                    }
                }
                else
                {
                    double h = 0.0;
                    switch (w)
                    {
                        case 0: h = m.map(value); break;
//                        case 1: h = dm.map(value); break;
//                        case 2: h = dn.map(value); break;
                    }
                    double s = 1.0;
                    double l = 0.5;
                    double r,g,b;
                    hsl2rgb(h,s,l,&r,&b,&g);
                    for (int ii = 0; ii < magnify; ++ii)
                    {
                        for (int jj = 0; jj < magnify; ++jj)
                        {
                            switch (w)
                            {
                                case 0: image.plot    (magnify * (i1 - s1) + ii, magnify * (i2 - s2) + jj, r, g, b); break;
//                                case 1: diffimage.plot(magnify * (i1 - s1) + ii, magnify * (i2 - s2) + jj, r, g, b); break;
//                                case 2: minimage.plot (magnify * (i1 - s1) + ii, magnify * (i2 - s2) + jj, r, g, b); break;
                            }
                        }
                    }
                }
            }
        } 
    } 
    image.close();
//    diffimage.close();
//    minimage.close();
}

#define PrintInt(a); \
    fprintf(tfp, "%s=%d\n", #a, a);

#define Print(a); \
    fprintf(tfp, "%s=%f\n", #a, a);

#define PrintArray1D(m,a,s,e); \
    fprintf(tfp,"%s\n",m); \
    for (tmp1 = s; tmp1 <= e; ++tmp1) \
    { \
        fprintf(tfp, "%s[%d]=%f\n", #a, tmp1, a[tmp1]); \
    } \
    fflush(tfp);

#define PrintArray2D(s,a,s1,e1,s2,e2); \
    { \
    std::string file = std::string(#a) + std::string(s) + ".txt"; \
    FILE *fp = fopen(file.c_str(), "w"); \
    for (tmp1 = s1; tmp1 <= e1; ++tmp1) \
    { \
        for (tmp2 = s2; tmp2 <= e2; ++tmp2) \
        { \
            fprintf(tfp, "%s[%d][%d]=%f\n", #a, tmp1, tmp2, a[tmp1][tmp2]); \
        } \
    } \
    fclose(fp); \
    }

#define PrintArray2Dcoded(s,a,s1,e1,s2,e2); \
    { \
    std::string file = std::string(#a) + std::string(s) + ".txt"; \
    int filled = 0; \
    FILE *fp = fopen(file.c_str(), "w"); \
    for (tmp1 = s1; tmp1 <= e1; ++tmp1) \
    { \
        fprintf(fp, "%3d ", tmp1); \
        for (tmp2 = s2; tmp2 <= e2; ++tmp2) \
        { \
            char c = code(a[tmp1][tmp2]); \
            fprintf(fp, "%c ", c); \
            if (c != '.') ++filled; \
        } \
        fprintf(fp, "\n"); \
    } \
    fprintf(fp, "%4.1f %% filled\n", 100.0 * filled / ((e1 - s1 + 1) * (e2 - s2 + 1))); \
    fclose(fp); \
    }

#define PlotArrayContents(s,a,s1,e1,s2,e2); \
    { \
        PlotArray(std::string(#a) + std::string(s), a, s1, e1, s2, e2); \
    }

#endif
